#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Err.hpp"
#include "Log.hpp"

// setsockopt 是一个用于设置套接字选项的系统调用。
// 它允许应用程序在已打开的套接字上设置各种选项，以控制套接字的行为和属性。
// int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
// sockfd：套接字文件描述符。
// level：选项所属协议层，常见的值包括 SOL_SOCKET（通用套接字选项）和特定协议的协议层（例如 IPPROTO_TCP）。
// optname：选项名称，用于指定要设置的具体选项。
// optval：指向存储新选项值的缓冲区的指针。
// optlen：缓冲区的长度。

namespace zxf
{
    class Sock
    {
        static const int backlog = 10;
    public:
        Sock() :_listenSock(-1)
        {
        }
        ~Sock()
        {
            if(_listenSock > 0 )
            {
                close(_listenSock);
            }
        }
        void Socket()
        {
            // 1. 创建socket文件套接字对象
            _listenSock = socket(AF_INET, SOCK_STREAM, 0);
            if (_listenSock < 0)
            {
                logMessage(FATAL, "create socket error");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL, "create socket success: %d", _listenSock);

            int opt = 1;
            int ret = setsockopt(_listenSock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
            if (ret == -1)
            {
                logMessage(FATAL, "setsockopt error: %s ", strerror(errno));
                exit(SETSOCKOPT_ERR);
            }
            logMessage(NORMAL, "setsockopt socket SO_REUSEADDR success!!");
            // 常见的选项与其对应的 optname 值有以下几个例子（并非完整列表）：
            // SO_REUSEADDR：允许地址重用。
            // SO_KEEPALIVE：启用或禁用 TCP 的 Keep-Alive 功能。
            // SO_RCVBUF 和 SO_SNDBUF：设置接收和发送缓冲区大小。
            // TCP_NODELAY：禁用 Nagle 算法，提高发送小数据包的效率。
        }

        void Bind(int port)
        {
            // 2. bind绑定自己的网络信息
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(port);
            local.sin_addr.s_addr = INADDR_ANY;
            if (bind(_listenSock, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                logMessage(FATAL, "bind socket error");
                exit(BIND_ERR);
            }
            logMessage(NORMAL, "bind socket success");
        }

        void Listen()
        {
            // 3. 设置socket 为监听状态
            if (listen(_listenSock, backlog) < 0) // backlog+1全连接队列的长度
            {
                logMessage(FATAL, "listen socket error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL, "listen socket success");
        }

        int Accept(std::string *clientip, uint16_t *clientport)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sock = accept(_listenSock, (struct sockaddr *)&peer, &len);
            if (sock < 0)
                logMessage(ERROR, "accept error, next");
            else
            {
                logMessage(NORMAL, "accept a new link success, get new sock: %d", sock);
                if (clientip)
                {
                    *clientip = inet_ntoa(peer.sin_addr);
                }
                if (clientport)
                {
                    *clientport = ntohs(peer.sin_port);
                }
            }
            return sock;
        }

        int fd()
        {
            return _listenSock;
        }

    private:
        int _listenSock = -1;
    };

}